package com.ray.depot.service.impl;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.ray.api.service.ActivitiApiService;
import com.ray.common.util.RedisNoUtil;
import com.ray.depot.common.util.Constans;
import com.ray.depot.enums.InOutType;
import com.ray.depot.enums.StockChangeStatus;
import com.ray.depot.service.InOutRecordService;
import com.ray.depot.service.StockChangeRecordService;
import com.ray.depot.service.StockChangeSerializeService;
import com.ray.depot.service.StockChangeService;
import com.ray.depot.table.entity.InOut;
import com.ray.depot.table.entity.InOutSerialize;
import com.ray.depot.table.entity.StockChange;
import com.ray.depot.table.entity.StockChangeRecord;
import com.ray.depot.table.entity.StockChangeRecordExample;
import com.ray.depot.table.entity.StockChangeRecordExample.Criteria;
import com.ray.depot.table.entity.StockChangeSerialize;
import com.ray.depot.table.mapper.StockChangeRecordMapper;
import com.ray.depot.table.vo.ChangeVo;
import com.ray.depot.table.vo.RecordVo;
import com.xiaoleilu.hutool.util.StrUtil;
import com.zjhc.flyhong.common.function.enums.DeleteEnum;
import com.zjhc.flyhong.common.function.exception.BussinessException;
import com.zjhc.flyhong.common.function.operator.LoginUser;
import com.zjhc.flyhong.common.function.operator.PageDto;
import com.zjhc.flyhong.common.function.validate.EntityValidate;
import com.zjhc.flyhong.common.function.validate.rule.FieldRule;
import com.zjhc.flyhong.common.function.validate.rule.RuleEnum;
import com.zjhc.flyhong.common.util.UUIDUtil;
import com.zjhc.flyhong.common.web.ErrorMsg;
import com.zjhc.flyhong.common.web.Result;
import com.zjhc.flyhong.common.web.SuccessMsg;
import com.zjhc.flyhong.common.web.base.BaseService;
import com.zjhc.flyhong.redis.DefaultRedisService;

@Service
public class StockChangeRecordServiceImpl extends BaseService implements StockChangeRecordService {
	/** 日志对象 **/
	private static Logger logger = Logger.getLogger(StockChangeRecordServiceImpl.class);

	@Autowired
	private StockChangeRecordMapper stockChangeRecordMapper;
	@Autowired
	private StockChangeSerializeService stockChangeSerializeService;
	@Autowired
	private StockChangeService stockChangeService;
	@Autowired
	private DefaultRedisService defaultRedisService;
	@Autowired
	private ActivitiApiService activitiApiService;
	@Autowired
	private InOutRecordService inOutRecordService;

	
	@Transactional
	public Result<Object> addStockChangeRecord(StockChangeRecord params, LoginUser user) {
		Result<Object> result = null;
		result = new Result<Object>(0, SuccessMsg.OP_SUCCESS);
		params.setTenantId(user.getTenantId());
		params.setId(UUIDUtil.getUUID());
		params.setIsDelete(DeleteEnum.USE.getValue());
		this.setUserForAdd(params, user);
		int count = stockChangeRecordMapper.insertSelective(params);
		if (count != 1) {
			logger.error("StockChangeRecordServiceImpl=>addStockChangeRecord is error");
			throw new BussinessException(-1, ErrorMsg.INSERT_ERROR);
		}
		return result;
	}

	@Transactional(propagation = Propagation.NOT_SUPPORTED)
	public StockChangeRecord queryStockChangeRecord(String id, LoginUser user) {
		return stockChangeRecordMapper.selectByPrimaryKey(id);
	}

	@Transactional
	public Result<Object> updateStockChangeRecord(StockChangeRecord params, LoginUser user) {
		Result<Object> result = null;
		result = new Result<Object>(0, SuccessMsg.OP_SUCCESS);
		this.setUserForUpdate(params, user);
		int count = stockChangeRecordMapper.updateByPrimaryKeySelective(params);
		if (count != 1) {
			logger.error("StockChangeRecordServiceImpl=>editStockChangeRecord is error");
			throw new BussinessException(-1, ErrorMsg.INSERT_ERROR);
		}
		return result;
	}

	@Transactional
	public Result<Object> deleteStockChangeRecord(String id, LoginUser user) {
		Result<Object> result = null;
		result = new Result<Object>(0, SuccessMsg.OP_SUCCESS);
		StockChangeRecord params = new StockChangeRecord();
		params.setId(id);
		params.setIsDelete(DeleteEnum.DELETE.getValue());
		this.setUserForUpdate(params, user);
		int count = stockChangeRecordMapper.updateByPrimaryKeySelective(params);
		if (count != 1) {
			logger.error("StockChangeRecordServiceImpl=>deleteStockChangeRecord is error");
			throw new BussinessException(-1, ErrorMsg.INSERT_ERROR);
		}
		return result;
	}

	@Transactional(propagation = Propagation.NOT_SUPPORTED)
	public PageDto<StockChangeRecord> queryStockChangeRecord(StockChangeRecord params, PageDto<StockChangeRecord> page, LoginUser user) {
		StockChangeRecordExample example = new StockChangeRecordExample();
		Criteria criteria = example.createCriteria();
		// 超级管理员能查看全部
		if (!user.isSuperManager()) {
			criteria.andTenantIdEqualTo(user.getTenantId());
		} else if (user.isManager()) {
			criteria.andCreateByOrgEqualTo(user.getDeptCode());
		} else {
			criteria.andCreateByUserEqualTo(user.getUserId());
		}

		
		criteria.andIsDeleteEqualTo(DeleteEnum.USE.getValue());
		this.setExamplePage(example, page);
		page.setTotal(stockChangeRecordMapper.countByExample(example));
		page.setRecords(stockChangeRecordMapper.selectByExample(example));
		return page;
	}

	@Override
	@Transactional
	public Result<Object> saveChangeRecord(ChangeVo record, Boolean isDaft, LoginUser user) {
		record.setStatus(StockChangeStatus.draft.getType());
		// 草稿状态下不需要校验
		if (!isDaft) {
			// 对象验证
			FieldRule fieldRule = new FieldRule();
			fieldRule.addRule(RuleEnum.IS_NOT_NULL, String.class, "sourceWarchouseId", "来源仓库");
			fieldRule.addRule(RuleEnum.IS_NOT_NULL, String.class, "targetWarchouseId", "目标仓库");
			Result<Object> result = EntityValidate.validate(record, fieldRule);
			if (!result.codeSuccess()) {
				return result;
			}

			// 校验是否为空
			if (record.getInOuts().isEmpty() && record.getInOutSerializes().isEmpty()) {
				return new Result<>(-1, "没有入库的物料或资产");
			}
			
			// 仓库是否一样
			if (StrUtil.equals(record.getSourceWarchouseId(), record.getTargetWarchouseId())) {
				return new Result<>(-1, "目标仓库和来源仓库不能一样");
			}
			
			// 物料校验
			if (!record.getInOuts().isEmpty()) {
				for (StockChange StockChange : record.getInOuts()) {
					 fieldRule = new FieldRule();
					 fieldRule.addRule(RuleEnum.IS_NOT_NULL, Integer.class, "quantity", "数量");
					 result = EntityValidate.validate(StockChange, fieldRule);
					 if (!result.codeSuccess()) {
						return result;
					}
				}
			}
			//资产校验
			if (!record.getInOutSerializes().isEmpty()) {
				for (StockChangeSerialize StockChangeSerialize : record.getInOutSerializes()) {
					 fieldRule = new FieldRule();
					 fieldRule.addRule(RuleEnum.IS_NOT_NULL, String.class, "serializaNo", "资产号");
					 result = EntityValidate.validate(StockChangeSerialize, fieldRule);
					 if (!result.codeSuccess()) {
						return result;
					}
				}
			}
			
			record.setStatus(StockChangeStatus.ToSubmit.getType());
		}

		String stockChangeNo = RedisNoUtil.createNo("TC", defaultRedisService);
		record.setRecordNo(stockChangeNo);
		// 插入头
		this.addStockChangeRecord(record, user);
		// 插入物料
		if (!record.getInOuts().isEmpty()) {
			for (StockChange stockChange : record.getInOuts()) {
				stockChange.setRecordNo(stockChangeNo);
				stockChangeService.addStockChange(stockChange, user);
			}
		}
		// 插入资产
		if (!record.getInOutSerializes().isEmpty()) {
			for (StockChangeSerialize stockChangeSerialize : record.getInOutSerializes()) {
				stockChangeSerialize.setRecordNo(stockChangeNo);
				stockChangeSerializeService.addStockChangeSerialize(stockChangeSerialize, user);
			}
		}
		return new Result<>(0, SuccessMsg.OP_SUCCESS);
	}

	@Override
	@Transactional
	public Result<Object> editChangeRecord(ChangeVo record, LoginUser user) {
		 StockChangeRecord StockChangeRecord = this.queryStockChangeRecord(record.getId(), user);
		 //判断自有在草稿 审核不同意 带提交的时候才能修改
		 if(!StockChangeStatus.canEdit(StockChangeRecord.getStatus())){
			 return new Result<>(-1, "该状态不能编辑");
		 }
		// 草稿状态下不需要校验
		// 对象验证
		FieldRule fieldRule = new FieldRule();
		fieldRule.addRule(RuleEnum.IS_NOT_NULL, String.class, "sourceWarchouseId", "来源仓库");
		fieldRule.addRule(RuleEnum.IS_NOT_NULL, String.class, "targetWarchouseId", "目标仓库");
		fieldRule.addRule(RuleEnum.IS_NOT_NULL, String.class, "recordNo", "调仓单号");
		Result<Object> result = EntityValidate.validate(record, fieldRule);
		if (!result.codeSuccess()) {
			return result;
		}
		// 校验是否为空
		if (record.getInOuts().isEmpty() && record.getInOutSerializes().isEmpty()) {
			return new Result<>(-1, "没有入库的物料或资产");
		}
		
		// 仓库是否一样
		if (StrUtil.equals(record.getSourceWarchouseId(), record.getTargetWarchouseId())) {
			return new Result<>(-1, "目标仓库和来源仓库不能一样");
		}

		String stockChangeNo = record.getRecordNo();
		//审批驳回状态 不用修改
		if(!StrUtil.equals(StockChangeRecord.getStatus(), StockChangeStatus.ApplyFail.getType())){
			record.setStatus(StockChangeStatus.ToSubmit.getType());
		}
		// 插入头
		this.updateStockChangeRecord(record, user);
		// 插入物料
		// 先删除物料
		stockChangeService.deleteStockChangeByNo(stockChangeNo, user);
		if (!record.getInOuts().isEmpty()) {
			for (StockChange stockChange : record.getInOuts()) {
				stockChange.setRecordNo(stockChangeNo);
				stockChangeService.addStockChange(stockChange, user);
			}
		}
		// 插入资产
		// 先删除资产
		stockChangeSerializeService.deleteStockChangeSerializeByNo(stockChangeNo, user);
		if (!record.getInOutSerializes().isEmpty()) {
			for (StockChangeSerialize stockChangeSerialize : record.getInOutSerializes()) {
				stockChangeSerialize.setRecordNo(stockChangeNo);
				stockChangeSerializeService.addStockChangeSerialize(stockChangeSerialize, user);
			}
		}

		return new Result<>(0, SuccessMsg.OP_SUCCESS);
	}

	@Override
	@Transactional
	public Result<Object> deleteChangeRecord(String id, LoginUser user) {
		StockChangeRecord StockChangeRecord = this.queryStockChangeRecord(id, user);
		if(!StockChangeStatus.canDelete(StockChangeRecord.getStatus())){
			 return new Result<>(-1, "该状态不能删除");
		 }
		String StockChangeNo = StockChangeRecord.getRecordNo();
		// 删除头
		this.deleteStockChangeRecord(id, user);
		// 先删除物料
		stockChangeService.deleteStockChangeByNo(StockChangeNo, user);
		// 先删除资产
		stockChangeSerializeService.deleteStockChangeSerializeByNo(StockChangeNo, user);
	   return new Result<>(0, SuccessMsg.OP_SUCCESS);
	}

	@Override
	@Transactional
	public Result<Object> applyRecord(String stockChangeNo,String userids, String deployId, String defId, String actKey, LoginUser user) {
		StockChangeRecord StockChangeRecord = this.queryStockChangeRecordByStockChangeNo(stockChangeNo, user);
		if(!StockChangeStatus.canSubmitApply(StockChangeRecord.getStatus())){
			 return new Result<>(-1, "该状态不能审核");
		 }
		//更新订单状态
		try {
			activitiApiService.startFlow(stockChangeNo, actKey, userids, deployId, defId, user);
		} catch (Exception e) {
			 throw new  BussinessException(-1,"流程启动异常");
		}
		return new Result<>(0, SuccessMsg.OP_SUCCESS);
	}
	
	public StockChangeRecord queryStockChangeRecordByStockChangeNo(String stockChangeNo, LoginUser user) {
		StockChangeRecordExample example = new StockChangeRecordExample();
		example.createCriteria().andRecordNoEqualTo(stockChangeNo)
		.andIsDeleteEqualTo(DeleteEnum.USE.getValue());
		List<StockChangeRecord> lists =  stockChangeRecordMapper.selectByExample(example);
		if(lists == null || lists.isEmpty()){
			throw new BussinessException(-1, "不存在该记录");
		}
		if(lists.size() >1){
			throw new BussinessException(-1, "查询到多条该记录");
		}
		return lists.get(0);
	}

	@Override
	@Transactional
	public void applyFail(String StockChangeNo) {
		//更新订单状态
		updateStatusByStockChangeNo(StockChangeNo,StockChangeStatus.ApplyFail.getType(),null);
	}
	
	@Override
	@Transactional
	public void applySuccess(String StockChangeNo) {
		//更新订单状态
		updateStatusByStockChangeNo(StockChangeNo,StockChangeStatus.ToChange.getType(),null);
	}
	
	@Override
	@Transactional
	public void applyIng(String StockChangeNo) {
		//更新订单状态
		updateStatusByStockChangeNo(StockChangeNo,StockChangeStatus.ToApply.getType(),null);
	}
	
	@Override
	@Transactional
	public void applyCancel(String StockChangeNo) {
		//更新订单状态
		updateStatusByStockChangeNo(StockChangeNo,StockChangeStatus.ApplyCancel.getType(),null);
	}
 
	

	   /**********************************/
		@Transactional
		private void updateStatusByStockChangeNo(String StockChangeNo, String status, LoginUser user) {
			StockChangeRecordExample example = new StockChangeRecordExample();
			example.createCriteria().andRecordNoEqualTo(StockChangeNo);
			StockChangeRecord entity = new StockChangeRecord();
			entity.setStatus(status);
			//this.setUserForUpdate(entity, user);
			stockChangeRecordMapper.updateByExampleSelective(entity, example);
		}
		/**
		 * 更新zhiangt
		 * @param stockChangeNo
		 * @param entity
		 * @param user
		 */
		@Transactional
		private void updateByStockChangeNo(String stockChangeNo, StockChangeRecord entity , LoginUser user) {
			StockChangeRecordExample example = new StockChangeRecordExample();
			example.createCriteria().andRecordNoEqualTo(stockChangeNo);
			this.setUserForUpdate(entity, user);
			stockChangeRecordMapper.updateByExampleSelective(entity, example);
		}
        /**
         * 预占
         */
		@Override
		@Transactional
		public Result<Object> changeIn(String id, LoginUser user) {
			StockChangeRecord stockChangeRecord = this.queryStockChangeRecord(id, user);
			if(!StockChangeStatus.canChange(stockChangeRecord.getStatus())){
				 return new Result<>(-1, "该状态不能调仓");
			 }
			stockChangeRecord.setStatus(StockChangeStatus.ChangeSuccess.getType());
			
			List<StockChange> stockChanges = stockChangeService.queryStockChangesByStockChangeNo(stockChangeRecord.getRecordNo(), user);
			List<StockChangeSerialize> stockChangeSerializes = stockChangeSerializeService.queryStockChangeSerializesByStockChangeNo(stockChangeRecord.getRecordNo(), user);
			RecordVo record = new RecordVo(); 
			record.setSourceId(Constans.BGS_ID);
			
			 
			List<InOut> inOuts = new ArrayList<InOut>();
			List<InOutSerialize> inOutSerializes = new ArrayList<InOutSerialize>();
			InOut inOut = null;
			for(StockChange stockChange : stockChanges){
				inOut = new InOut();
				try {
					PropertyUtils.copyProperties(inOut,stockChange);
				} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
					throw new BussinessException(-1, "数据转换异常.");
				}
				inOuts.add(inOut);
			}
			record.setInOuts(inOuts);
			//资产
			InOutSerialize inOutSerialize = null;
			for(StockChangeSerialize stockChangeSerialize : stockChangeSerializes){
				inOutSerialize = new InOutSerialize();
				try {
					PropertyUtils.copyProperties(inOutSerialize,stockChangeSerialize);
				} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
					throw new BussinessException(-1, "数据转换异常.");
				}
				inOutSerializes.add(inOutSerialize);
			}
			record.setInOutSerializes(inOutSerializes);
			//生成待出库单
			record.setWarchouseId(stockChangeRecord.getSourceWarchouseId());//来源仓库出库
			record.setInOutType(InOutType.ChangeOut.getType());
			RecordVo sourceRecordVo = inOutRecordService.saveOutRecordAndDoOut(record, user);
			
			record.setWarchouseId(stockChangeRecord.getTargetWarchouseId());//目标仓库入库
			record.setInOutType(InOutType.ChangeIn.getType());
			RecordVo targetRecordVo = inOutRecordService.saveInRecordAndDoIn(record, user);
			
			stockChangeRecord.setOutNo(sourceRecordVo.getInOutNo());//出库单号
			stockChangeRecord.setInNo(targetRecordVo.getInOutNo());//入库单号
			updateByStockChangeNo(stockChangeRecord.getRecordNo(),stockChangeRecord,user);
			
			return new Result<>(0, SuccessMsg.OP_SUCCESS);
		}
	

}
